package eip.chapter3.pointtopoint.impl;

import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mule.extras.client.MuleClient;
import org.mule.umo.UMOException;

import eip.chapter3.pointtopoint.HotelBooking;
import eip.chapter3.pointtopoint.HotelBookingClient;
import eip.chapter3.pointtopoint.RoomType;

public class HotelBookingClientImpl implements HotelBookingClient {

	private static final Logger logger = Logger.getLogger(HotelBookingClientImpl.class);
	private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
	private final Namespace hotelNamespace = new Namespace("slb", HotelBooking.SB_NAMESPACE);
	private String target;
	
	public void sendBooking(HotelBooking booking) {
		try {
			String message = createXMLHotelBooking(booking); 
			MuleClient client = new MuleClient();
			if(logger.isInfoEnabled()) {
				logger.info("Sending message " + message + " to " + target);
			}
			client.dispatch(target,message,null);
		} catch (UMOException umoE) {
			logger.error("Error sending message to target: " + target, umoE);
		} catch (IOException ioExc) {
			logger.error("Error creating XML message", ioExc);
		}
	}
	
//	---------------------------------------------
	// Private helper methods
	//---------------------------------------------
	
	private String createXMLHotelBooking(HotelBooking booking) throws IOException {
	    Element bookingElem = DocumentHelper.createElement(HotelBooking.HOTEL_BOOKING);
	    bookingElem.add(hotelNamespace);
	    addElement(HotelBooking.NAME, booking.getName(), bookingElem);
	    addElement(HotelBooking.ADDRESS, booking.getAddress(), bookingElem);
	    addElement(HotelBooking.BOOKING_DATE, booking.getBookingDate(), bookingElem);
	    addElement(HotelBooking.ROOM_TYPE, booking.getRoomType(), bookingElem);
	    addElement(HotelBooking.ARRIVAL_DATE, booking.getArrivalDate(), bookingElem);
	    addElement(HotelBooking.CHECKOUT_DATE, booking.getCheckoutDate(), bookingElem);
	    addElement(HotelBooking.SMOKING, booking.getSmoking(), bookingElem);
		
		bookingElem.add(DocumentHelper.createAttribute(bookingElem, HotelBooking.BOOKING_ID, 
				booking.getBookingID().toString()));
	    XMLWriter writer = new XMLWriter(OutputFormat.createPrettyPrint());
	    StringWriter stringWriter = new StringWriter();
	    writer.setWriter(stringWriter);
	    writer.write(bookingElem);
	    return stringWriter.toString();
	}
	
	private Element addElement(String elementName, String value, Element parentElem) {
		Element newElem = DocumentHelper.createElement(new QName(elementName, hotelNamespace));
		newElem.setText(value);
		parentElem.add(newElem);
		return newElem;
	}
	
	private Element addElement(String elementName, Date value, Element parentElem) {
		String strValue = dateFormat.format(value);
		return addElement(elementName, strValue, parentElem);
	}
	
	private Element addElement(String elementName, RoomType value, Element parentElem) {
		String strValue = null;
		if(RoomType.SINGLE_ROOM.equals(value)) {
			strValue = RoomType.XML_SINGLE_ROOM;
		} else if(RoomType.DOUBLE_ROOM.equals(value)) {
			strValue = RoomType.XML_DOUBLE_ROOM;
		} else if(RoomType.SUITE.equals(value)) {
			strValue = RoomType.XML_SUITE;
		}
		return addElement(elementName, strValue, parentElem);
	}
	
	private Element addElement(String elementName, Boolean value, Element parentElem) {
		String strValue = null;
		if(value == null || value.booleanValue() == false) {
			strValue = "No";
		} else {
			strValue = "Yes";
		}
		return addElement(elementName, strValue, parentElem);
	}
	
//	---------------------------------------------
	// Simple setters and getters
	//---------------------------------------------

	public String getTarget() {
		return target;
	}

	public void setTarget(String target) {
		this.target = target;
	}

}
